{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 读取Excel生成PDF报告"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. 引入相关包"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import matplotlib\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "plt.rcParams['font.sans-serif'] = ['SimHei']\n",
    "\n",
    "# 安装方法：pip install reportlab\n",
    "from reportlab.pdfbase import pdfmetrics\n",
    "from reportlab.pdfbase.ttfonts import TTFont\n",
    "from reportlab.lib.styles import getSampleStyleSheet,ParagraphStyle\n",
    "from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer,Image,Table,TableStyle\n",
    "from reportlab.lib import colors\n",
    "from reportlab.lib.pagesizes import A4\n",
    "from reportlab.lib.units import inch\n",
    "\n",
    "### 设置中文字体名称为微软雅黑，msyh.ttf需要自己指定文件路径\n",
    "pdfmetrics.registerFont(TTFont('msyh', 'msyh.ttf'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2. 数据统计"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>语文</th>\n",
       "      <th>数学</th>\n",
       "      <th>英语</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>姓名</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>张伟</th>\n",
       "      <td>94</td>\n",
       "      <td>79</td>\n",
       "      <td>63</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>王伟</th>\n",
       "      <td>79</td>\n",
       "      <td>91</td>\n",
       "      <td>77</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>王芳</th>\n",
       "      <td>99</td>\n",
       "      <td>69</td>\n",
       "      <td>46</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    语文  数学  英语\n",
       "姓名            \n",
       "张伟  94  79  63\n",
       "王伟  79  91  77\n",
       "王芳  99  69  46"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df = pd.read_excel(\"./数据-学生成绩表.xlsx\", index_col='姓名')\n",
    "df.head(3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>统计项</th>\n",
       "      <th>语文</th>\n",
       "      <th>数学</th>\n",
       "      <th>英语</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>count</td>\n",
       "      <td>50.00</td>\n",
       "      <td>50.00</td>\n",
       "      <td>50.00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>mean</td>\n",
       "      <td>71.80</td>\n",
       "      <td>66.96</td>\n",
       "      <td>69.68</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>std</td>\n",
       "      <td>17.23</td>\n",
       "      <td>15.49</td>\n",
       "      <td>18.13</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>min</td>\n",
       "      <td>40.00</td>\n",
       "      <td>41.00</td>\n",
       "      <td>41.00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>25%</td>\n",
       "      <td>59.50</td>\n",
       "      <td>54.25</td>\n",
       "      <td>53.25</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>50%</td>\n",
       "      <td>73.00</td>\n",
       "      <td>67.50</td>\n",
       "      <td>70.50</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>75%</td>\n",
       "      <td>86.00</td>\n",
       "      <td>76.00</td>\n",
       "      <td>82.50</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>max</td>\n",
       "      <td>99.00</td>\n",
       "      <td>100.00</td>\n",
       "      <td>100.00</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "     统计项     语文      数学      英语\n",
       "0  count  50.00   50.00   50.00\n",
       "1   mean  71.80   66.96   69.68\n",
       "2    std  17.23   15.49   18.13\n",
       "3    min  40.00   41.00   41.00\n",
       "4    25%  59.50   54.25   53.25\n",
       "5    50%  73.00   67.50   70.50\n",
       "6    75%  86.00   76.00   82.50\n",
       "7    max  99.00  100.00  100.00"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 描述性统计\n",
    "df_desc = (\n",
    "    df\n",
    "    .describe()\n",
    "    .applymap(lambda x : round(x, 2))\n",
    "    .reset_index()\n",
    "    .rename(columns={'index':'统计项'})\n",
    ")\n",
    "df_desc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 3 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 输出统计图\n",
    "df.plot.hist(bins=20, subplots=True)\n",
    "plt.savefig('plot.png')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3. 开始构建PDF，添加标题文字"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 容纳所有的PDF的内容\n",
    "elements = []\n",
    "\n",
    "# 读取reportlab定义好的样式表\n",
    "style = getSampleStyleSheet()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 大标题\n",
    "title = \"\"\" <para> <font face=\"msyh\"> 考生成绩统计报告 </font> </para>\"\"\"\n",
    "elements.append(Paragraph(title, style['Heading1']))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4. 添加表格"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[['统计项', '语文', '数学', '英语'],\n",
       " ['count', 50.0, 50.0, 50.0],\n",
       " ['mean', 71.8, 66.96, 69.68],\n",
       " ['std', 17.23, 15.49, 18.13],\n",
       " ['min', 40.0, 41.0, 41.0],\n",
       " ['25%', 59.5, 54.25, 53.25],\n",
       " ['50%', 73.0, 67.5, 70.5],\n",
       " ['75%', 86.0, 76.0, 82.5],\n",
       " ['max', 99.0, 100.0, 100.0]]"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 转换成数组\n",
    "table_data  = [list(df_desc.columns)] + df_desc.to_numpy().tolist()\n",
    "table_data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 小标题\n",
    "title = \"\"\" <para> <font face=\"msyh\"> 统计明细 </font> </para>\"\"\"\n",
    "elements.append(Paragraph(title, style['Heading2']))\n",
    "\n",
    "# 表格对象\n",
    "mytable = Table(table_data)\n",
    "mytab_style = TableStyle([\n",
    "    ('GRID', (0,0), (-1,-1), 1, colors.black),\n",
    "    ('FONTSIZE', (0,0), (-1,-1), 12),\n",
    "    ('ALIGN', (0,-1), (-1,-1), 'LEFT'),\n",
    "    ('FONT', (0,0), (-1,-1), 'msyh')\n",
    "])\n",
    "mytable.setStyle(mytab_style)\n",
    "\n",
    "# 添加对象\n",
    "elements.append(mytable)\n",
    "elements.append(Spacer(1, 0.2*inch))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5. 添加图片"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 添加一个小标题\n",
    "elements.append(\n",
    "    Paragraph(\"\"\"<para><font face=\"msyh\">成绩分布</font></para>\"\"\", \n",
    "              style[\"Heading2\"]))\n",
    "\n",
    "# 添加图片\n",
    "img = Image('plot.png')\n",
    "elements.append(img)\n",
    "elements.append(Spacer(1, 0.2*inch))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 6. 生成PDF文件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "doc = SimpleDocTemplate(\"学生成绩统计报告.pdf\", pagesize=(A4[0], A4[1]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "doc.build(elements)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
